/**
 * \file Declaration.cpp
 * \brief Implementation of declaration-oriented Code subclasses
 * \author Wouter Caarls <w.caarls@tnw.tudelft.nl> 
 *
 * \verbatim
 * Copyright (c) 2005 Wouter Caarls, Delft University of Technology
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * \endverbatim
 */

#include <assert.h>

#include "Code.h"
#include "Expression.h"
#include "Declaration.h"
#include "Value.h"
#include "Symbol.h"

/* ************************************************************************* */

Code *TypeId::reduce(SymbolTable *symbols, Compound *out, Use use)
{
  TypeSymbol *tsym = dynamic_cast<TypeSymbol*>(symbols->findSymbol(name));
  
  if (!tsym)
    error(CStr("Type '") << name << "' doesn't exist");

  type = tsym->data;

  return new VoidValue();
}

std::string TypeId::toString(int indentation)
{
  return (char*)(CStr(indent(indentation)) << name);
}

std::string TypeId::toTerm()
{
  return (char*)(CStr("TypeId(\"") << name << "\")");
}

/* ************************************************************************* */

Code *TypeDecode::reduce(SymbolTable *symbols, Compound *out, Use use)
{
  Expression *res = data->reduce(symbols, out, AsExpression);
  CodeValue *code = dynamic_cast<CodeValue*>(res);

  if (code)
  {
    Id *id = dynamic_cast<Id*>(code->data);
    TypeName *tname = dynamic_cast<TypeName*>(code->data);

    if (id)
    {
      TypeId *tid = new TypeId(&Unknown, id->name);
      delete tid->reduce(symbols, out, use);
      type = tid->type;
      delete tid;
    }
    else if(tname)
    {
      delete tname->reduce(symbols, out, use);
      type = tname->type;
    }
    else
      LOG(plog.warning, HDR << "Decoded value does not represent a type '"
	  << code->data->toString() << "'" << std::endl);
  }
  else
  {
    LOG(plog.warning, HDR << "Decoding a non-code value '" << res->toString() << "'"
	<< std::endl);
    return res;
  }

  return new VoidValue();
}

std::string TypeDecode::toString(int indentation)
{
  return (char*)(CStr(indent(indentation)) << "@(" << data->toString() << ")");
}

std::string TypeDecode::toTerm()
{
  return (char*)(CStr("TypeDecode(\"") << data->toTerm() << "\")");
}

/* ************************************************************************* */

MemDecl* MemDecl::copy()
{
  return new MemDecl(typespec->copy(), iddecl->copy());
}

Code *MemDecl::reduce(SymbolTable *symbols, Compound *out, Use use)
{
  delete typespec->reduce(symbols, out, NotUsed);
  iddecl->type = iddecl->id->type = constructType(typespec->type, iddecl->derefs, symbols);
  iddecl->type = iddecl->id->type = constructType(iddecl->type, iddecl->bounds, symbols);

  return new VoidValue();
}

std::string MemDecl::toString(int indentation)
{
  if (iddecl->toString() == "") return "";

  return
    (char*)(CStr(typespec->toString(indentation)) << " " << iddecl->toString() << ";\n");
}

std::string MemDecl::toTerm()
{
  return (char*)(CStr("MemDecl(") << typespec->toTerm() << ", " << iddecl->toTerm() << ")");
}

/* ************************************************************************* */

Code *StructSpec::reduce(SymbolTable *symbols, Compound *out, Use use)
{
  StructType *stype = new StructType();


  if (!memdecls.empty())
    for (MI ii=memdecls.begin(); ii != memdecls.end(); ++ii)
    {
      delete (*ii)->reduce(symbols, out, use);
      Id *id = DecodeId((*ii)->iddecl->id, symbols, out);

      stype->push_back(new SubType(id->name,
				   (*ii)->iddecl->id->type));

      delete id;
    }

  TypeSymbol *tsym = dynamic_cast<TypeSymbol*>(symbols->findSymbol(stype->toString()));

  if (tsym)
  {
    delete stype;
    type = tsym->data;
  }
  else
  {
    symbols->addSymbol(new TypeSymbol(stype->toString(), stype));
    type = stype;
  }

  return new VoidValue();
}

std::string StructSpec::toString(int indentation)
{
  CStr res;

  res << indent(indentation) << "struct {\n";

  if (!memdecls.empty())
    for (MI ii=memdecls.begin(); ii != memdecls.end(); ++ii)
      res << (*ii)->toString(indentation+1);

  res << indent(indentation) << "}";

  return (char*)res;  
}

std::string StructSpec::toTerm()
{
  CStr res;

  res << "Struct(None, [";

  if (!memdecls.empty())
    for (MI ii=memdecls.begin(); ii != memdecls.end(); ++ii)
    {
      res << (*ii)->toTerm();
      if (ii != memdecls.end()-1)
	res << ", ";
    }

  res << "])";

  return (char*)res;
}

/* ************************************************************************* */

Code *TypeSpec::reduce(SymbolTable *symbols, Compound *out, Use use)
{
  if (spec)
  {
    delete spec->reduce(symbols, out);
    type = spec->type;
  }

  return new VoidValue();
}

std::string TypeSpec::toString(int indentation)
{
  if (spec)
    return spec->toString(indentation);
  else
    return type->_toString(true, indentation);
}

std::string TypeSpec::toTerm()
{
  if (spec)
    return (char*)(CStr("TypeSpec([], ") << spec->toTerm() << ", [])");
  else
    return type->toTerm();
}

/* ************************************************************************* */

Code *TypeName::reduce(SymbolTable *symbols, Compound *out, Use use)
{
  delete typespec->reduce(symbols, out);
  type = constructType(typespec->type, derefs, symbols);
  type = constructType(typespec->type, bounds, symbols);

  return new VoidValue();
}

std::string TypeName::toString(int indentation)
{
  CStr res;

  res << typespec->toString(indentation) << " ";
  if (!derefs.empty())
    for (DI ii=derefs.begin(); ii != derefs.end(); ++ii)
      res << (*ii)->toString();
  if (!bounds.empty())
    for (BI ii=bounds.begin(); ii != bounds.end(); ++ii)
      if ((*ii)->castToInteger() != -1)
	res << "[" << (*ii)->toString() << "]";
      else
	res << "[]";

  return (char*)res;
}

std::string TypeName::toTerm()
{
  CStr res;

  res << "TypeName(" << typespec->toTerm() << ", ";

  if (!derefs.empty())
  {
    res << "Some(Pointer([";
    for (DI ii=derefs.begin(); ii != derefs.end(); ++ii)
    {
      res << (*ii)->toTerm();
      if (ii != derefs.end()-1)
	res << ", ";
    }
    res << "], ";
  }

  if (!bounds.empty())
  {
    res << "Some([";
    for (BI ii=bounds.begin(); ii != bounds.end(); ++ii)
    {
      if ((*ii)->castToInteger() != -1)
	res << "ArrayDecl(" << (*ii)->toTerm() << ")";
      else
	res << "EmptyArrayDecl";
      if (ii != bounds.end()-1)
	res << ", ";
    }
    res << "])";
  }
  else
    res << "None";

  if (!derefs.empty())
    res << "))";

  res << ")";

  return (char*) res;
}

void TypeName::push_back(PointerOf *d)
{
  derefs.push_back(d);
}

void TypeName::push_back(IntegerValue *b)
{
  bounds.push_back(b);
}

/* ************************************************************************* */

ParamDecl::~ParamDecl()
{
  delete typespec;
  if (iddecl)
    delete iddecl;
}

ParamDecl *ParamDecl::copy()
{
  if (iddecl)
    return new ParamDecl(typespec->copy(), iddecl->copy());
  else
    return new ParamDecl(typespec->copy(), NULL);
}

Code *ParamDecl::reduce(SymbolTable *symbols, Compound *out, Use use)
{
  delete typespec->reduce(symbols, out, NotUsed);
  
  if (iddecl)
  {
    iddecl->type = iddecl->id->type = constructType(typespec->type, iddecl->derefs, symbols);
    iddecl->type = iddecl->id->type = constructType(iddecl->type, iddecl->bounds, symbols);
  }

  return new VoidValue();
}

std::string ParamDecl::toString(int indentation)
{
  if (iddecl)
  {
    if (iddecl->toString() == "") return "";

    return (char*)(CStr(typespec->toString(indentation)) << " "
		   << iddecl->toString());
  }
  else
    return (char*)(CStr(typespec->toString(indentation)));
}

std::string ParamDecl::toTerm()
{
  if (iddecl)
    return (char*)(CStr("ParamDecl(") << typespec->toTerm() << ", Some("
		   << iddecl->toTerm() << "))");
  else
    return (char*)(CStr("ParamDecl(") << typespec->toTerm() << ", None)");
}

/* ************************************************************************* */

std::string PointerOf::toString(int indentation)
{
  CStr res;

  if (isConst) res << "const";
  if (isVolatile)
  {
    if (res.str().length())
      res << " ";
    res << "volatile";
  }
  if (isRestrict)
  {
    if (res.str().length())
      res << " ";
    res << "restrict";
  }

  return (char*)(CStr("*") << res.str().c_str());
}

std::string PointerOf::toTerm()
{
  CStr res;

  if (isConst) res << "Const";
  if (isVolatile)
  {
    if (res.str().length())
      res << ", ";
    res << "Volatile";
  }
  if (isRestrict)
  {
    if (res.str().length())
      res << ", ";
    res << "Restrict";
  }

  return (char*)(CStr("PointerOf([") << res.str().c_str() << "])");
}

/* ************************************************************************* */

Code *IdDecl::reduce(SymbolTable *symbols, Compound *out, Use use)
{
  if (!params.empty())
    for (PI ii=params.begin(); ii != params.end(); ++ii)
      delete (*ii)->reduce(symbols, out);

  if (init)
  {
    Stat *stat = new Stat(new Assign(id->type, AssignEq, DecodeId(id, symbols, out), init->copy()));
    delete stat->reduce(symbols, out);
    delete stat;
  }

  return new VoidValue();
}

std::string IdDecl::toString(int indentation)
{
  CStr res; 
  typedef std::list<std::string>::iterator LI;

  Id* did = dynamic_cast<Id*>(id);

  if (!options.suppressDeclarations.empty())
    for (LI ii=options.suppressDeclarations.begin();
	 ii != options.suppressDeclarations.end(); ++ii)
      if (did && (*ii) == did->name)
	return "";

  if (!options.outputDeclarations && (!params.empty() || varargparam))
    return "";

  res << indent(indentation);
  if (!derefs.empty())
    for (DI ii=derefs.begin(); ii != derefs.end(); ++ii)
      res << (*ii)->toString();

  res << " " << id->toString();

  if (!params.empty() || varargparam)
    res << "(";

  if (!params.empty())
    for (PI ii=params.begin(); ii != params.end(); ++ii)
    {
      res << (*ii)->toString();
      if (ii != params.end()-1)
	res << ", ";
    }

  if (varargparam)
  {
    if (!params.empty())
      res << ", ";

    res << varargparam->toString() << "...";
  }

  if (!params.empty() || varargparam)
    res << ")";

  if (!bounds.empty())
  {
    for (BI ii=bounds.begin(); ii != bounds.end(); ++ii)
    {
      if ((*ii)->castToInteger() != -1)
	res << "[" << (*ii)->toString() << "]";
      else
	res << "[]";
    }
  }

  if (init)
  {
    res << " = " << init->toString();
  }
  
  return (char*)res;
}

std::string IdDecl::toTerm()
{
  CStr res;

  if (init)
    res << "DeclInit(";

  res << "IdDecl([";

  if (!derefs.empty())
    for (DI ii=derefs.begin(); ii < derefs.end(); ++ii)
    {
      res << (*ii)->toTerm();
      if (ii < derefs.end()-1)
        res << ", ";
    }
  
  res << "], " << id->toTerm() << ", ";

  if (params.empty())
  {
    if (bounds.size())
    {
      res << "Some([";
      for (BI ii=bounds.begin(); ii != bounds.end(); ++ii)
      {
	if ((*ii)->castToInteger() != -1)
	  res << "ArrayDecl(" << (*ii)->toTerm() << ")";
	else
	  res << "EmptyArrayDecl";
	if (ii != bounds.end()-1)
	  res << ", ";
      }
      res << "])";
    }
    else
      res << "None";
  }
  else
  {
    res << "Some(ParamList([";
  
    for (PI ii=params.begin(); ii != params.end(); ++ii)
    {
      res << (*ii)->toTerm();
      if (ii != params.end()-1)
	res << ", ";
    }
    
    res << "]))";
  }

  res << ")";

  if (init)
    res << ", AssignInit(" << init->toTerm() << "))";
  
  return (char*)res;
}

void IdDecl::push_back(PointerOf *d)
{
  derefs.push_back(d);
}
  
void IdDecl::push_back(ParamDecl *p)
{
  params.push_back(p);
}
  
void IdDecl::push_back(IntegerValue *b)
{
  bounds.push_back(b);
}
  
/* ************************************************************************* */

Code *Declaration2::reduce(SymbolTable *symbols, Compound *out, Use use)
{
  plog.reduce() << HDR << this->toString();
  setLastStatement(this);

  if (iddecls.empty())
    return new VoidValue();

  delete typespec->reduce(symbols, out);

  for (II ii=iddecls.begin(); ii != iddecls.end(); ++ii)
  {
    Type *type, *eltype;

    /* Build types. Pointers first */
    eltype = constructType(typespec->type, (*ii)->derefs, symbols);

    /* Then array dimensions */
    type = constructType(eltype, (*ii)->bounds, symbols);
    
    (*ii)->type = (*ii)->id->type = type;

    /* Now resolve a possible decoding in the identifier name */
    Id *id = DecodeId((*ii)->id, symbols, out);

    // (newdecl will be registered as being the declaration of (*ii), so that it may
    // be toStringd if (*ii) is residualized somewhere.
    Declaration2 *newdecl = new Declaration2(new TypeSpec(typespec->type), true, isStatic, isAuto, isPromote, isExtern);
    newdecl->push_back((*ii)->copy());

    // Replace with possibly decoded id
    delete newdecl->iddecls.back()->id;
    newdecl->iddecls.back()->id = id;
    
    // Don't use initializer if newdecl is residualized
    delete newdecl->iddecls.back()->init;
    newdecl->iddecls.back()->init = NULL;

    if ((*ii)->params.empty())
    {
      /* Variable declaration */
      /* Build value */
      Value *val = eltype->makeValue();
      val->adddeclaration(newdecl);
      
      Type *arrtype = eltype;

      IdDecl::RBI jj;
      
      for (jj = (*ii)->bounds.rbegin(); jj != (*ii)->bounds.rend(); ++jj)
      {
	CStr arrname;

                               	arrname << arrtype->toString() << "[";
	if ((*jj)->data != -1)  arrname << (*jj)->data;
                              	arrname << "]";

	TSymbol *arrsymbol = symbols->findSymbol((char*)arrname);
	if (!arrsymbol)
	  error(CStr("Couldn't find type symbol for ") << (char*)arrname);

	TypeSymbol *arrtypesymbol = dynamic_cast<TypeSymbol*>(arrsymbol);
	if (!arrtypesymbol)
	  error(CStr(arrname) << " is not a TypeSymbol");

	arrtype = arrtypesymbol->data;
	if (!arrtype)
	  error(CStr("TypeSymbol") << (char*)arrname << " doesn't contain data");

        newdecl->refcount++;
   	  val = new ArrayValue(arrtype, val, (*jj)->data);
	  val->adddeclaration(newdecl);
	newdecl->refcount--;
      }
            
      Variable *var =
	new Variable(id->name, val, newdecl);

#if 1
      if (symbols->findSymbol(id->name))
      { 
#endif
	symbols->addSymbol(var);
	out->push_back_decl(newdecl);
#if 1
      }
      else
      {
	symbols->addSymbol(var, isPromote);
	
	Compound *declout = out, *runner=out;

        if (isPromote)
  	  while (runner->parent)
          {
            runner = runner->parent;
            if (!runner->decls.empty())
   	      declout=runner;
          }

	declout->push_back_decl(newdecl);
      }
#endif
      
      delete (*ii)->reduce(symbols, out);    
    }
    else
    {
      /* Forward function declaration */
      // *** OR, FUNCTION POINTER DECLARATION, BUT WE DON'T DO FUNCTION POINTERS ***
      
      if (!symbols->findSymbol(id->name))
      {      
	delete (*ii)->reduce(symbols, out);

	FunDef *fdef = new FunDef(new TypeSpec(type), (*ii)->copy(), NULL);
	Function *function = new Function(id->name, fdef, NULL, newdecl, isExtern);

	symbols->addSymbol(function, isPromote);

	Compound *declout = out, *runner=out;

        if (isPromote)
  	  while (runner->parent)
          {
            runner = runner->parent;
            if (!runner->decls.empty())
   	      declout=runner;
          }

	declout->push_back_decl(newdecl);
      }      
    }
  }

  return new VoidValue();
}

void Declaration2::residualize(SymbolTable *symbols)
{
  if (tentative)
  {
    tentative = false;

    plog.residualize() << HDR << "residualizing declaration " << toString();

    if (typespec->type->sym && typespec->type->sym->def)
    {
      typespec->type->sym->def->residualize(symbols);
      typespec->type->sym->def = NULL;
    }
  }

  // *** Residualize inits ***
}

std::string Declaration2::toString(int indentation)
{
  CStr res;

  if ((tentative && !g_outputTentative) || iddecls.empty())
    return "";

  res << indent(indentation);

  if (isExtern) res << "extern ";
  if (isStatic) res << "static ";
  if (isAuto) res << "auto ";
  if (options.outputPromote && isPromote) res << "promote ";

  res << typespec->toString() << " ";

  for (II ii=iddecls.begin(); ii != iddecls.end(); ++ii)
  {
    if ((*ii)->toString() == "") return "";

    res << (*ii)->toString();
    if (ii != iddecls.end()-1)
      res << ", ";
  }  

  res << ";\n";

  return (char*)res;
}

std::string Declaration2::toTerm()
{
  CStr res;

  if (iddecls.empty())
    return (char*)(CStr("Declaration2(") << typespec->toTerm() << ", [])");

  res << "Declaration2(";

  if (isStatic || isAuto || isPromote || isExtern)
  {
    res << "DeclSpec([";
    if (isExtern) res << "Extern";

    if (isStatic)
    {
      if (isExtern)
        res << ", ";
      res << "Static";
    }
    if (isAuto)
    {
      if (isStatic || isExtern)
        res << ", ";
      res << "Auto";
    }
    if (isPromote)
    {
      if (isStatic || isAuto || isExtern)
        res << ", ";
      res << "Promote";
    }
    res << "],";
  }
  res << typespec->toTerm();

  if (isStatic || isAuto || isPromote || isExtern) res << ")";

  res << ",[";

  for (II ii=iddecls.begin(); ii != iddecls.end(); ++ii)
  {
    res << (*ii)->toTerm();
    if (ii != iddecls.end()-1)
      res << ", ";
  }  

  res << "])";

  return (char*)res;
}

void Declaration2::push_back(IdDecl *i)
{
  assert(i != NULL);

  iddecls.push_back(i);
}

void Declaration2::clear(void)
{
  if (!refcount)
    error("Declaration reference count fell below zero");

  refcount--;

  if (!refcount)
  {
    bool outputTentative = g_outputTentative;
    g_outputTentative = true;

    plog.residualize() << HDR << "clearing declaration " << toString() << std::endl;

    g_outputTentative = outputTentative;

    delete typespec;
    typespec = new TypeSpec(&BasicVoid);
    if (!iddecls.empty())
      for (II ii=iddecls.begin(); ii != iddecls.end(); ++ii)
        delete *ii;
    iddecls.clear();
  }
}
  
/* ************************************************************************* */

Code *FunDef::reduce(SymbolTable *symbols, Compound *out, Use use)
{
  plog.reduce() << HDR << this->toString();
  setLastStatement(this);

  delete typespec->reduce(symbols, out, NotUsed);
  iddecl->type = iddecl->id->type = constructType(typespec->type, iddecl->derefs, symbols);
  delete iddecl->reduce(symbols, out, NotUsed);

  Id *id = dynamic_cast<Id*>(iddecl->id);
  if (!id)
    error("Cannot decode function name in definition");

  if (!symbols->findSymbol(id->name))
  {
    FunDef *newdef = new FunDef(typespec->copy(), iddecl->copy(), data->copy(), true, isStatic, isAuto, isPromote, isExtern);
    Function *fun = new Function(id->name, this->copy(), newdef);
    
    symbols->addSymbol(fun, isPromote);

    Compound *defout = out, *runner=out;

    if (isPromote)
      while (runner->parent)
      {
        runner = runner->parent;
        if (!runner->decls.empty())
          defout=runner;
      }

    defout->push_back_decl(newdef);
  }
  else
  {
    plog.reduce() << HDR << "redefinition of function " << id->name << std::endl;
  }

  return new VoidValue();
}

std::string FunDef::toString(int indentation)
{
  CStr res;

  if (tentative || !options.outputDefinitions || iddecl->toString() == "")
    return "";

  res << indent(indentation);
  if (isExtern) res << "extern ";
  if (isStatic) res << "static ";
  if (isAuto) res << "auto ";
  if (options.outputPromote && isPromote) res << "promote ";

  res << typespec->toString() << " " << iddecl->toString()
      << "\n" << data->toString(indentation) << "\n";  

  return (char*)res;
}

std::string FunDef::toTerm()
{
  CStr res;

  res << "FunDef(";

  if (isStatic || isAuto || isPromote || isExtern)
  {
    res << "DeclSpec([";
    if (isExtern) res << "Extern";

    if (isStatic)
    {
      if (isExtern)
        res << ", ";
      res << "Static";
    }
    if (isAuto)
    {
      if (isStatic || isExtern)
        res << ", ";
      res << "Auto";
    }
    if (isPromote)
    {
      if (isStatic || isAuto || isExtern)
        res << ", ";
      res << "Promote";
    }
    res << "],";
  }
  res << typespec->toTerm();

  if (isStatic || isAuto || isPromote || isExtern) res << ")";

  res << ", " << iddecl->toTerm() << ", " << data->toTerm() << ")";

  return (char*)res;
}

/* ************************************************************************* */

Code *StrategyDef::reduce(SymbolTable *symbols, Compound *out, Use use)
{
  plog.reduce() << HDR << this->toString();
  setLastStatement(this);

  delete typespec->reduce(symbols, out, NotUsed);
  iddecl->type = iddecl->id->type = constructType(typespec->type, iddecl->derefs, symbols);

  Id *id = dynamic_cast<Id*>(iddecl->id);
  if (!id)
    error("Cannot decode strategy name in definition");

  if (!symbols->findSymbol(id->name))
  {
    StrategyDef *newdef = new StrategyDef(iddecl->copy(), data->copy(), true);
    Strategy *strat = new Strategy(id->name, this->copy(), newdef);
    
    symbols->addSymbol(strat);
    
    out->push_back_decl(newdef);
  }
  else
  {
    plog.reduce() << HDR << "redefinition of strategy " << id->name << std::endl;
  }

  return new VoidValue();
}

std::string StrategyDef::toString(int indentation)
{
  if (tentative || !options.outputDefinitions || iddecl->toString() == "")
    return "";

  return (char*)(CStr(indent(indentation)) << "strategy "
		 << iddecl->toString()
		 << "\n" << data->toString(indentation) << "\n");
}

std::string StrategyDef::toTerm()
{
  return (char*)(CStr("StrategyDef(") << iddecl->toTerm()
		 << ", " << data->toTerm() << ")");
}

/* ************************************************************************* */

Code *TypeDef::reduce(SymbolTable *symbols, Compound *out, Use use)
{
  plog.reduce() << HDR << this->toString();
  setLastStatement(this);

  delete typespec->reduce(symbols, out, NotUsed);

  Id *id = dynamic_cast<Id*>(iddecl->id);
  if (!id)
    error("Cannot decode typename in definition");

  if (!symbols->findSymbol(id->name))
  {
    /* Make sure our own typespec won't be associated with a type symbol */
    Type *type = typespec->type->copy();

    /* Build types. Pointers first */
    type = constructType(type, iddecl->derefs, symbols);

    /* Then array dimensions */
    type = constructType(type, iddecl->bounds, symbols);

    iddecl->type = iddecl->id->type = type;

    TypeDef *newdef = new TypeDef(typespec->copy(), iddecl->copy(), true);
    TypeSymbol *tsym = new TypeSymbol(id->name, type, newdef);

    symbols->addSymbol(tsym);

    out->push_back_decl(newdef);
  }
  else
  {
    plog.reduce() << HDR << "redefinition of type " << id->name << std::endl;
  }

  return new VoidValue();
}

void TypeDef::residualize(SymbolTable *symbols)
{
  if (tentative)
  {
    tentative = false;
    
    LOG(plog.debug, HDR << "residualizing typedef " << toString() << std::endl);
  }
}

std::string TypeDef::toString(int indentation)
{
  if (tentative || !options.outputDefinitions || iddecl->toString() == "")
    return "";

  return (char*)(CStr(indent(indentation)) << "typedef\n"
		 << typespec->toString(indentation+1) << " " << iddecl->toString()
		 << ";\n");
}

std::string TypeDef::toTerm()
{
  return (char*)(CStr("TypeDef(") << typespec->toTerm()
		 << ", " << iddecl->toTerm() << ")");
}
